package jfoo.detailsTable;

import java.awt.Color;
import java.awt.Component;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.Toolkit;
import java.awt.datatransfer.Clipboard;
import java.awt.datatransfer.StringSelection;
import java.awt.dnd.DropTarget;
import java.awt.event.ActionEvent;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.util.EventObject;
import java.util.Random;

import javax.swing.AbstractAction;
import javax.swing.DropMode;
import javax.swing.JComponent;
import javax.swing.JTable;
import javax.swing.ListSelectionModel;
import javax.swing.SwingUtilities;
import javax.swing.event.TableModelEvent;
import javax.swing.table.TableCellRenderer;

import jfoo.ControlCenter;
import jfoo.playlist.PlaylistList;
import jfoo.playlist.PlaylistListModel;
import audio.AudioFile;

/*TODO :
 * http://www.jroller.com/nweber/entry/multi_column_sorting_w_mustang
 * 
 */

public class DetailsTable extends JTable implements MouseListener, KeyListener {

	private DetailsTableModel model;

	private ControlCenter controlCenter;
	private int oldPlayingIndex = -1; // used to fire a repaint of the table
	private PlaylistList playlistList;
	DetailsTableTransferHandler detailsTableTransferHandler;

	private Random random;

	public DetailsTable(DetailsTableModel model, ControlCenter controlCenter, PlaylistList playlistList) {
		super(model);

		this.model = model;
		this.controlCenter = controlCenter;
		this.playlistList = playlistList;
		controlCenter.setDetailsTable(this);
		this.setDoubleBuffered(true);
		setFillsViewportHeight(true);
		setCellSelectionEnabled(true);
		setSelectionMode(ListSelectionModel.MULTIPLE_INTERVAL_SELECTION);

		// monTableau.setRowHeight(xApercu);
		// monTableau.setIntercellSpacing(new Dimension(10, 15));
		// monTableau.setShowGrid(false);
		// monTableau.getTableHeader().setReorderingAllowed(false);
		// monTableau.getTableHeader().setResizingAllowed(false);

		setShowHorizontalLines(false);
		setShowVerticalLines(true);
		detailsTableTransferHandler = new DetailsTableTransferHandler(this);
		playlistList.setDetailsTableTransferHandler(detailsTableTransferHandler);
		setDropTarget(new DropTarget(this, detailsTableTransferHandler.getDropHandler()));
		setDragEnabled(true);
		setDropMode(DropMode.ON_OR_INSERT_ROWS);
		setTransferHandler(detailsTableTransferHandler);
		addMouseListener(this);

		setAutoCreateRowSorter(true);

		addMouseListener(this);
		addKeyListener(this);
		setGridColor(new Color(221, 221, 221));
		// setSelectionBackground(arg0);
		// setSelectionForeground(arg0);
		// setBackground();
		// setForeground(arg0));
		DetailsTableCellEditor ed = new DetailsTableCellEditor();
		setCellEditor(ed);

		setDefaultRenderer(String.class, new StringTableCellRenderer(this));

		setColumnSelectionAllowed(false);
		setRowSelectionAllowed(true);

		CopyToClipBoardAction copyToClipBoardAction = new CopyToClipBoardAction();

		getActionMap().put("copy", copyToClipBoardAction);

		// getInputMap().put(KeyStroke.getKeyStroke("F3"),
		// copyAction);

		getColumnModel().getColumn(0).setMinWidth(30);
		getColumnModel().getColumn(0).setMaxWidth(30);
		getColumnModel().getColumn(0).setPreferredWidth(20);
		getColumnModel().getColumn(1).setPreferredWidth(180);
		getColumnModel().getColumn(2).setPreferredWidth(200);
		// getColumnModel().getColumn(1).setMaxWidth(210); // artist
		// getColumnModel().getColumn(2).setMaxWidth(340); // title

		getColumnModel().getColumn(3).setMaxWidth(40);
		getColumnModel().getColumn(3).setMaxWidth(40);
		getColumnModel().getColumn(4).setMaxWidth(40);
		// getColumnModel().getColumn(5).setMaxWidth(180); // album
		getColumnModel().getColumn(5).setPreferredWidth(180);

		getColumnModel().getColumn(6).setMaxWidth(80);
		getColumnModel().getColumn(7).setMaxWidth(200);

		// editing conveniences
		putClientProperty("JTable.autoStartsEdit", Boolean.FALSE);
		putClientProperty("terminateEditOnFocusLost", Boolean.TRUE);

	}

	// hack to disable editing from a mouse event. I don't know how to disable the doubleclick edit in fact
	public boolean editCellAt(int row, int column, EventObject e) {
		if (e.getClass().getName().equals("java.awt.event.MouseEvent")) {
			return false;
		} else {
			return super.editCellAt(row, column, e);
		}
	}

	@Override
	public void tableChanged(TableModelEvent e) {
		super.tableChanged(e);
		System.out.println("event " + e.toString() + " ; " + e.getType() + " ; " + e.getFirstRow() + " ; " + e.getLastRow());
		/* gestion du dernier audio selectionné */
		if ((e.getType() == 0) && (e.getFirstRow() == 0) && (e.getLastRow() == Integer.MAX_VALUE)) { // detailTable has switched
			// to another playlist
			int selectedIndex = model.getLastSelectedIndex();

			if ((selectedIndex == -1) && (model.getRowCount() != 0)) {
				// clearSelection();
				addRowSelectionInterval(0, 0);
			} else if ((selectedIndex != -1) && (selectedIndex < model.getRowCount())) {

				addRowSelectionInterval(selectedIndex, selectedIndex);
			}

		}

	}


	public void handleCurrentPlaying(AudioFile f) {
		int index = model.getAudioFiles().indexOf(f);
		((PlaylistListModel) playlistList.getModel()).handleCurrentPlaying(model.getPlaylist(), index);
		
		if (index != -1) {
			int playingIndex = convertRowIndexToView(model.getAudioFiles().indexOf(f));

		
			model.fireTableRowsUpdated(playingIndex, playingIndex);
			
			if ((oldPlayingIndex != -1) && (model.getRowCount() > oldPlayingIndex)) {
				model.fireTableRowsUpdated(oldPlayingIndex, oldPlayingIndex);
			}

			oldPlayingIndex = playingIndex;

			clearSelection();
			setRowSelectionInterval(playingIndex, playingIndex);

		} else {
			oldPlayingIndex = -1;
		}

	}

	public int getCurrentPlayingIndex() {
		return model.getPlaylist().getCurrentlyPlayingIndex();
	}

	public void setCurrentPlayingIndex(int currentPlayingIndex) {
		model.getPlaylist().setCurrentlyPlayingIndex(currentPlayingIndex);
	}

	public DetailsTableModel getDetailsTableModel() {
		return this.model;
	}

	public ControlCenter getControlCenter() {
		return controlCenter;
	}

	@Override
	public boolean isCellEditable(int rowIndex, int columnIndex) {

		switch (columnIndex) {
		case 0:
			return false;
		case 1:
			return true;
		case 2:
			return true;
		case 3: // time
			return false;
		case 4:
			return true;
		case 5:
			return true;
		case 6:
			return true;
		case 7: // lastModified
			return false;
		}
		return false;
	}

	public void next() {
		int index = convertRowIndexToModel(getSelectedRow());
		AudioFile audioFile = null;

		if ((index == -1) && (model.getRowCount() > 0)) {
			audioFile = (AudioFile) model.getElementAt(0);
			controlCenter.play(audioFile);

		} else if (!(controlCenter.getCurrentAudioFile().equals((AudioFile) model.getElementAt(index)))) {
			// if the user has moved the cursor during one song is played, the next one played is the one selected

			audioFile = (AudioFile) model.getElementAt(index);
			controlCenter.play(audioFile);

		} else if (model.getRowCount() > index + 1) {
			audioFile = (AudioFile) model.getElementAt(index + 1);
			controlCenter.play(audioFile);

		}
		if (audioFile != null) {
			controlCenter.play(audioFile);
		}
	}

	public void previous() {
		int index = getSelectedRow();
		if ((index == -1) && (model.getRowCount() > 0)) {
			AudioFile audioFile = (AudioFile) model.getElementAt(0);
			controlCenter.play(audioFile);
		} else if ((model.getRowCount() > index) && (index != 0)) {
			AudioFile audioFile = (AudioFile) model.getElementAt(index - 1);
			// set focus sur le previous
			setRowSelectionInterval(index - 1, index - 1);
			controlCenter.play(audioFile);
		}
	}

	public void random() {
		if (random == null) {
			random = new Random();
		}
		int n = model.getRowCount();
		int index = random.nextInt(n);
		AudioFile audioFile = (AudioFile) model.getElementAt(index);
		setRowSelectionInterval(index, index);
		controlCenter.play(audioFile);

	}

	public void play() {

		int index = getSelectedRow();
		if ((index == -1) && (model.getRowCount() > 0)) {
			AudioFile audioFile = (AudioFile) model.getElementAt(0);
			setRowSelectionInterval(0, 0);
			controlCenter.play(audioFile);
		} else {
			AudioFile audioFile = (AudioFile) model.getElementAt(index);
			controlCenter.play(audioFile);
		}
	}

	/*
	 * http://www.jroller.com/santhosh/date/20050625#partially_visible_tablecells used to display tooltip only if not all is
	 * visible
	 */

	public String convertValueToText(Object value, int row, int column) {
		if (value != null) {
			String sValue = value.toString();
			if (sValue != null)
				return sValue;
		}
		return "";
	}

	public String getToolTipText(MouseEvent event) {
		String tip = null;
		Point p = event.getPoint();

		// Locate the renderer under the event location
		int hitColumnIndex = columnAtPoint(p);
		int hitRowIndex = rowAtPoint(p);

		if ((hitColumnIndex != -1) && (hitRowIndex != -1)) {
			TableCellRenderer renderer = getCellRenderer(hitRowIndex, hitColumnIndex);
			Component component = prepareRenderer(renderer, hitRowIndex, hitColumnIndex);

			// Now have to see if the component is a JComponent before
			// getting the tip
			if (component instanceof JComponent) {
				// Convert the event to the renderer's coordinate system
				Rectangle cellRect = getCellRect(hitRowIndex, hitColumnIndex, false);
				if (cellRect.width >= component.getPreferredSize().width)
					return null;
				p.translate(-cellRect.x, -cellRect.y);
				MouseEvent newEvent = new MouseEvent(component, event.getID(), event.getWhen(), event.getModifiers(), p.x, p.y, event
						.getClickCount(), event.isPopupTrigger());

				tip = ((JComponent) component).getToolTipText(newEvent);
			}

			// No tip from the renderer, see whether any tooltip is set on JTable
			if (tip == null)
				tip = getToolTipText();

			// calculate tooltip from cell value
			if (tip == null) {
				Object value = getValueAt(hitRowIndex, hitColumnIndex);
				tip = convertValueToText(value, hitRowIndex, hitColumnIndex);
				if (tip.length() == 0)
					tip = null; // don't show empty tooltips
			}
		} // changed
		return tip;
	}

	// makes the tooltip's location to match table cell location
	// also avoids showing empty tooltips
	public Point getToolTipLocation(MouseEvent event) {
		int row = rowAtPoint(event.getPoint());
		if (row == -1)
			return null;
		int col = columnAtPoint(event.getPoint());
		if (col == -1)
			return null;

		// to avoid empty tooltips - return null location
		boolean hasTooltip = getToolTipText() == null ? getToolTipText(event) != null : true;

		return hasTooltip ? getCellRect(row, col, false).getLocation() : null;
	}

	// end of http://www.jroller.com/santhosh/date/20050625#partially_visible_tablecells

	public void mouseClicked(MouseEvent e) {
		if (e.getButton() == MouseEvent.BUTTON3) {
			System.out.println("Right Click........");
		}

		if (e.getClickCount() == 2 && SwingUtilities.isLeftMouseButton(e)) {

			try {
				int index = convertRowIndexToModel(rowAtPoint(e.getPoint()));
				AudioFile audioFile = (AudioFile) model.getElementAt(index);
				model.getPlaylist().setLastSelectedIndex(index);
				controlCenter.play(audioFile);
			} catch (java.lang.IndexOutOfBoundsException ex) {
				// convertRowIndexToModel failed
			}

		} else if (e.getClickCount() == 1 && SwingUtilities.isLeftMouseButton(e)) {
			try {
				int index = convertRowIndexToModel(rowAtPoint(e.getPoint()));

				model.getPlaylist().setLastSelectedIndex(index);
			} catch (java.lang.IndexOutOfBoundsException ex) {
				// convertRowIndexToModel failed
			}
		} else if (SwingUtilities.isMiddleMouseButton(e)) {
			try {
				int index = convertRowIndexToModel(rowAtPoint(e.getPoint()));
				AudioFile audioFile = (AudioFile) model.getElementAt(index);
			} catch (java.lang.IndexOutOfBoundsException ex) {
				// convertRowIndexToModel failed
			}

		}

	}

	public void keyPressed(KeyEvent e) {

		int touche = e.getKeyCode();
		if (touche == KeyEvent.VK_ENTER) {
			int index = getSelectedRow();
			AudioFile audioFile = (AudioFile) model.getElementAt(index);
			// setRowSelectionInterval(index, index);
			model.getPlaylist().setLastSelectedIndex(index);
			controlCenter.play(audioFile);
		}
	}

	public void keyReleased(KeyEvent e) {
	}

	public void keyTyped(KeyEvent e) {
	}


	public void mouseEntered(MouseEvent e) {
	}

	public void mouseExited(MouseEvent e) {
	}

	public void mousePressed(MouseEvent e) {
	}

	public void mouseReleased(MouseEvent e) {
	}


	class CopyToClipBoardAction extends AbstractAction {
		public CopyToClipBoardAction() {
			super();
			putValue(MNEMONIC_KEY, KeyEvent.VK_COPY);
		}

		public void actionPerformed(ActionEvent e) {
			int row = getSelectedRow();
			Clipboard systemClipboard = Toolkit.getDefaultToolkit().getSystemClipboard();
			String text = (String) getModel().getValueAt(row, 1) + " - " + (String) getModel().getValueAt(row, 2);
			StringSelection textSelection = new StringSelection(text);
			systemClipboard.setContents(textSelection, null);

		}
	}

}
